package com.gitee.l0km.aocache;

import org.aspectj.lang.ProceedingJoinPoint;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.nullToEmpty;

public class Timecost {

	/**
	 * 计算{@code runnable}的平均执行时间(纳秒)
	 * @param runnable
	 * @param runCount 执行次数，要求大于0
	 * @param title 日志输出首行字符串，为{@code null}忽略
	 * @param tail 日志输出尾部字符串，为{@code null}忽略
	 * @return 执行时间(纳秒)
	 */
	public static long test(Runnable runnable,int runCount, String title, String tail) {
		checkNotNull(runnable,"runnable is null");
		checkArgument(runCount > 0,"INVALID runCount %s",runCount);
		title = nullToEmpty(title);
		tail = nullToEmpty(tail);
		long startTime = System.nanoTime();
		long nanoseconds;
		try {
			for (int i = 0; i < runCount; ++i) {
				runnable.run();
			}
		} finally {
			nanoseconds = System.nanoTime() - startTime ;
		}
		/** 调用耗时(毫秒) */
		float milliseconds = nanoseconds / 1000000F;
		if(!title.isEmpty()) {
			AocacheLogger.DEFAULT.log(title);
		}
		if (runCount == 1) {
			AocacheLogger.DEFAULT.log(String.format("TIME COST: [%.4fms]%s", milliseconds,tail));
		} else {
			AocacheLogger.DEFAULT.log(String.format("TOTAL TIME COST: [%.4fms]", milliseconds));
			AocacheLogger.DEFAULT.log(String.format("AVG TIME COST: [%.4fms] for %d times%s", milliseconds / runCount,runCount,tail));
		}
		return nanoseconds/runCount;
	}
	/**
	 * 计算{@code runnable}的执行一次的时间(纳秒)
	 * @param runnable
	 * @param title 日志输出首行字符串，为{@code null}忽略
	 * @param tail 日志输出尾部字符串，为{@code null}忽略
	 * @return 执行时间(纳秒)
	 */
	public static long test(Runnable runnable, String title, String tail) {
		return test(runnable,1, title, tail);
	}
	/**
	 * 计算{@code runnable}的执行一次的时间(纳秒)
	 * @param runnable
	 * @return 执行时间(纳秒)
	 */
	public static long test(Runnable runnable) {
		return test(runnable,1, null, null);
	}
	/**
	 * 输出方法/构造方法执行时间
	 */
	public static Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		long startTime = System.nanoTime();
		long nanoseconds;
		try {
			return joinPoint.proceed();
		} finally {
			nanoseconds = System.nanoTime() - startTime ;
			/** 调用耗时(毫秒) */
			float milliseconds = nanoseconds / 1000000F;
			AocacheLogger.DEFAULT.log(String.format("\nTIME COST: [%.4fms]\n\t└─%s\n\t\t└─InvokeKey:%s", 
					milliseconds,joinPoint.toString(),
					new InvokeKey(joinPoint).toSimpleString()));
		}
	}
}
